///////////////////////////////////////////////////////////////////////////
// Copyright 2009 Arabic Game Developer Network, All rights reserved
// www.agd-online.com - info@agdn-online.com
// Based on code originally authored by Salwan Alhilali for the kvalley2 project
// Copyright 2008, In|Framez Co., All rights reserved
//
// File: input.h
// Description: Input system
//
///////////////////////////////////////////////////////////////////////////

// This file is part of kvalleyX.
// 
// kvalleyX is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// kvalleyX is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with kvalleyX.  If not, see <http://www.gnu.org/licenses/>.

#ifndef _INPUT_H
#define _INPUT_H

#include <map>

/////////////////// #defines ///////////////////
// Deadzone ranges from: 0 to: 10000
#define JOYSTICK_DEADZONE 3000

namespace CoreLib
{
//////////////////////////////////////////////////////
// Class: InputManager
// Purpose: Central input manager.
// Details: Uses DirectInput8 to read the keyboard and
//          one joystick.
//          Game controls can be assigned to multiple
//			keys. (Keys, Buttons, or Axis).
//////////////////////////////////////////////////////
class InputManager
{
	public:
		// General Key input codes
		enum InputKeyCode
		{
			INPUTK_BACKSPACE,	// 	'\b'	backspace
			INPUTK_TAB, 		//	'\t'	tab
			INPUTK_CLEAR,		//	 		clear
			INPUTK_RETURN,		//	'\r'	return
			INPUTK_PAUSE,		//		 	pause
			INPUTK_ESCAPE,		//	'^['	escape
			INPUTK_SPACE,		//	' '		space
			INPUTK_EXCLAIM,		//	'!'		exclaim
			INPUTK_QUOTEDBL,	//	'"'		quotedbl
			INPUTK_HASH,		//	'#'		hash
			INPUTK_DOLLAR,		//	'$'		dollar
			INPUTK_AMPERSAND,	//	'&'		ampersand
			INPUTK_QUOTE,		//	'''		quote
			INPUTK_LEFTPAREN,	//	'('		left parenthesis
			INPUTK_RIGHTPAREN,	//	')'		right parenthesis
			INPUTK_ASTERISK,	//	'*'		asterisk
			INPUTK_PLUS,		//	'+'		plus sign
			INPUTK_COMMA,		//	','		comma
			INPUTK_MINUS,		//	'-'		minus sign
			INPUTK_PERIOD,		//	'.'		period
			INPUTK_SLASH,		//	'/'		forward slash
			INPUTK_0,			//	'0'		0
			INPUTK_1,			//	'1'		1
			INPUTK_2,			//	'2'		2
			INPUTK_3,			//	'3'		3
			INPUTK_4,			//	'4'		4
			INPUTK_5,			//	'5'		5
			INPUTK_6,			//	'6'		6
			INPUTK_7,			//	'7'		7
			INPUTK_8,			//	'8'		8
			INPUTK_9,			//	'9'		9
			INPUTK_COLON,		//	':'		colon
			INPUTK_SEMICOLON,	//	';'		semicolon
			INPUTK_LESS,		//	'<'		less-than sign
			INPUTK_EQUALS,		//	'='		equals sign
			INPUTK_GREATER,		//	'>'		greater-than sign
			INPUTK_QUESTION,	//	'?'		question mark
			INPUTK_AT,			//	'@'		at
			INPUTK_LEFTBRACKET,	//	'['		left bracket
			INPUTK_BACKSLASH,	//	'\'		backslash
			INPUTK_RIGHTBRACKET,//	']'		right bracket
			INPUTK_CARET,		//	'^'		caret
			INPUTK_UNDERSCORE,	//	'_'		underscore
			INPUTK_BACKQUOTE,	//	'`'		grave
			INPUTK_a,			//	'a'		a
			INPUTK_b,			//	'b'		b
			INPUTK_c,			//	'c'		c
			INPUTK_d,			//	'd'		d
			INPUTK_e,			//	'e'		e
			INPUTK_f,			//	'f'		f
			INPUTK_g,			//	'g'		g
			INPUTK_h,			//	'h'		h
			INPUTK_i,			//	'i'		i
			INPUTK_j,			//	'j'		j
			INPUTK_k,			//	'k'		k
			INPUTK_l,			//	'l'		l
			INPUTK_m,			//	'm'		m
			INPUTK_n,			//	'n'		n
			INPUTK_o,			//	'o'		o
			INPUTK_p,			//	'p'		p
			INPUTK_q,			//	'q'		q
			INPUTK_r,			//	'r'		r
			INPUTK_s,			//	's'		s
			INPUTK_t,			//	't'		t
			INPUTK_u,			//	'u'		u
			INPUTK_v,			//	'v'		v
			INPUTK_w,			//	'w'		w
			INPUTK_x,			//	'x'		x
			INPUTK_y,			//	'y'		y
			INPUTK_z,			//	'z'		z
			INPUTK_DELETE,		//	'^?'	delete
			INPUTK_KP0,			//	 		keypad 0
			INPUTK_KP1,			//	 		keypad 1
			INPUTK_KP2,			//		 	keypad 2
			INPUTK_KP3,			//		 	keypad 3
			INPUTK_KP4,			//		 	keypad 4
			INPUTK_KP5,			//		 	keypad 5
			INPUTK_KP6,			//		 	keypad 6
			INPUTK_KP7,			//		 	keypad 7
			INPUTK_KP8,			//		 	keypad 8
			INPUTK_KP9,			//		 	keypad 9
			INPUTK_KP_PERIOD,	//	'.'		keypad period
			INPUTK_KP_DIVIDE,	//	'/'		keypad divide
			INPUTK_KP_MULTIPLY,	//	'*'		keypad multiply
			INPUTK_KP_MINUS,	//	'-'		keypad minus
			INPUTK_KP_PLUS,		//	'+'		keypad plus
			INPUTK_KP_ENTER,	//	'\r'	keypad enter
			INPUTK_KP_EQUALS,	//	'='		keypad equals
			INPUTK_UP,			//	 		up arrow
			INPUTK_DOWN,		//	 		down arrow
			INPUTK_RIGHT,		//	 		right arrow
			INPUTK_LEFT,		//	 		left arrow
			INPUTK_INSERT,		//	 		insert
			INPUTK_HOME,		//	 		home
			INPUTK_END,			//	 		end
			INPUTK_PAGEUP,		//	 		page up
			INPUTK_PAGEDOWN,	//	 		page down
			INPUTK_F1,			//	 		F1
			INPUTK_F2,			//	 		F2
			INPUTK_F3,			//	 		F3
			INPUTK_F4,			//	 		F4
			INPUTK_F5,			//	 		F5
			INPUTK_F6,			//	 		F6
			INPUTK_F7,			//	 		F7
			INPUTK_F8,			//	 		F8
			INPUTK_F9,			//	 		F9
			INPUTK_F10,			//	 		F10
			INPUTK_F11,			//	 		F11
			INPUTK_F12,			//	 		F12
			INPUTK_F13,			//	 		F13
			INPUTK_F14,			//	 		F14
			INPUTK_F15,			//	 		F15
			INPUTK_NUMLOCK,		//	 		numlock
			INPUTK_CAPSLOCK,	//	 		capslock
			INPUTK_SCROLLOCK,	//	 		scrollock
			INPUTK_RSHIFT,		//	 		right shift
			INPUTK_LSHIFT,		//	 		left shift
			INPUTK_RCTRL,		//	 		right ctrl
			INPUTK_LCTRL,		//	 		left ctrl
			INPUTK_RALT,		//	 		right alt
			INPUTK_LALT,		//	 		left alt
			INPUTK_RMETA,		//	 		right meta
			INPUTK_LMETA,		//	 		left meta
			INPUTK_LSUPER,		//	 		left windows key
			INPUTK_RSUPER,		//	 		right windows key
			INPUTK_MODE,		//	 		mode shift
			INPUTK_HELP,		//	 		help
			INPUTK_PRINT,		//	 		print-screen
			INPUTK_SYSREQ,		//	 		SysRq
			INPUTK_BREAK,		//	 		break
			INPUTK_MENU,		//	 		menu
			INPUTK_POWER,		//	 		power
			INPUTK_EURO		//	 		euro
		};

		enum InputEvent
		{
			InputEvent_KeyUp,
			InputEvent_KeyDown,
		};

		enum JoystickAxis
		{
			JoystickAxis_Up=1000,
			JoystickAxis_Down=1001,
			JoystickAxis_Right=1002,
			JoystickAxis_Left=1003,
		};

	protected:
		char m_cInjectedChar;	// Used to receive character input from the
								// message procedure (to be used for writing
								// password,...etc)
		
		std::multimap<int, int>	m_KeyboardActionMap;// A Multi-map is used so
													// that each event can be
													// assigned to multiple keys
													// at the same time.
		std::map<int, InputEvent> m_KeyboardActionEvents;	// Used to hold
															// input event
															// per-action
		int	m_iJoystickUp;
		int	m_iJoystickDown;
		int	m_iJoystickLeft;
		int	m_iJoystickRight;
		std::multimap<int, int>	m_JoystickActionMap;
		std::map<int, InputEvent> m_JoystickActionEvents;
		bool m_bJoystickReady;
		std::map<InputKeyCode, int> m_KeyCodeMap;

	public:
		InputManager();
		virtual ~InputManager();

		virtual bool init() = 0;
		void update(void);
		void KeyboardAssignControl(const int control, InputKeyCode keycode);
		void KeyboardRemoveControl(const int eGameControl);
		//void KeyboardRemoveControlKey(int eGameControl, int eDIKey);
		const bool ControlDown(const int eGameControl);
		void RemoveAllControls(void);

		void JoystickUpAssignControl(const int eGameControl);
		void JoystickDownAssignControl(const int eGameControl);
		void JoystickLeftAssignControl(const int eGameControl);
		void JoystickRightAssignControl(const int eGameControl);
		void JoystickButtonAssignControl(const int eGameControl, const int
iButton);
		void JoystickButtonRemoveControl(const int eGameControl);
		const bool HasJoystick(void) const{ return m_bJoystickReady; }
	// 	const int GetJoystickButtonCount(void)
	// 	{ return m_bJoystickReady? m_JoystickCaps.dwButtons : 0; }

		const char GetPressedCharacter(void);
		void _injectCharacter(const char cCharacterCode);

	// 	static InputManager* Instance; // Singleton
	// 	static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE
	// 	*pDeviceInstance, VOID* pContext);
	// 	static BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE
	// 	*pObjectInstance, VOID* pContext);

	protected:
		virtual void terminateDirectInput() = 0;
		virtual void pollKeyboard() = 0;
		virtual void pollJoystick() = 0;
};
} // CoreLib namespace

#endif // _INPUT_H

////////////////// End of File : input.h //////////////////